-module(routerc).
-export([init/1]).
-include_lib("records.hrl").

init(SrcId) ->
  RouterC = #routerc{id=SrcId},
  run(RouterC).

run(RouterC) ->
  #routerc{id=SrcId, outlines=Outlines, recpackets=Rec, losspackets=Loss} = RouterC,
  receive
    {_, {add_output, Outline}} ->
      %io:format("Add output line:~p~n",[Outline]),
      run(RouterC#routerc{outlines=[Outline|Outlines]});
    {From, result}->
      From ! {self(),Rec, Loss},
      run(RouterC);
    {From, close} ->
      From ! close;
    {From, {packet, Packet}} ->
      NewRec = [Packet|Rec],
      Next = next_srcid(SrcId, Packet),
      %io:format("~p Next Source Id:~p~n", [Packet, Next]),
      case Next of
        empty ->
          %io:format("Finish ~p~n",[Packet]),
          NewLoss = Loss;
        _ ->
          Result = alloc_packet(Outlines, Next, Packet),
          case Result of
            full ->
              NewLoss=[Packet|Loss];
            _ ->
              NewLoss = Loss
          end,
          From ! {self(), rec_ok}
      end,
      run(RouterC#routerc{recpackets=NewRec, losspackets=NewLoss})
  end.

next_srcid(Now, Packet) ->
  #packet{sources=Srcs} = Packet,
  get_next_srcid(Now, Srcs).

get_next_srcid(_, []) ->
  empty;

get_next_srcid(Now, [H|T]) ->
  if
    Now=:=H ->
      case T of
        [] ->
          get_next_srcid(Now, T);
        _ ->
          [N|_] = T,
          N
      end;
    true ->
      get_next_srcid(Now, T)
  end.

alloc_packet(Outlines, Next, Packet) ->
  %io:format("Find Outline from ~p~n", [Outlines]),
  Tid = get_next_outline(Outlines, Next),
  Tid ! {self(), {add, Packet}},
  receive
    {Tid, added} ->
      added;
    {Tid, full} ->
      full
  end.

get_next_outline([H|T], Next) ->
  H ! {self(), dest_id},
  receive
    {H, Id} ->
       DestId = Id
  end,
  %io:format("Outline Dest Id:~p~n", [DestId]),
  if
    DestId =:=Next ->
      H;
    true ->
      get_next_outline(T, Next)
  end.

